home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / TESTSPAR / ACSI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  14.6 KB  |  530 lines

  1. ;+
  2. ; Edit History
  3. ;
  4. ; May-22-89    ml.    Started this with AHDI 3.00.
  5. ; Aug-21-89    ml.    Added format code.  It's seperated because it waits
  6. ;            forever for command completion.
  7. ; Sep-08-89    ml.    Added a 1 microsec delay (rstdelay()) after each 
  8. ;            access to the DMA chip which may reset the chip.
  9. ; Sep-13-89    ml.    If need to execute a command more than once to
  10. ;            get all bytes into RAM, use the original allocation
  11. ;            length for subsequent calls.
  12. ; Oct-06-89    ml.    Added start/stop unit code.  It's seperated because
  13. ;            it needs longer timeouts.
  14. ; Nov-08-89    ml.    Added a delay in _rcvacsi() when looping to do more
  15. ;            than one _sblkacsi().
  16. ; Nov-27-89    ml.    Added .even after declaring control.
  17. ; Dec-05-89    ml.    Flushing of D cache before reading status byte.
  18. ; Apr-09-90    ml.    Added a "read" from WDL to actually "set" the bit
  19. ;            for the new MMU chip.  It's a bug in the chip.  
  20. ;            Temporary only.
  21. ; Apr-20-90    ml.    Made the "read" added on Apr-09-90 conditional
  22. ;            assembly.  RDWDL flag defined in defs.h.
  23. ; Sep-24-91    ml.    Added the _slwacsi flag to indicate whether we
  24. ;            are talking to a slow ACSI device.  If so, extra
  25. ;            delay is necessary to wait for the device to
  26. ;            response.
  27. ; Oct-07-91    ml.    Instead of using "lsr" to check if transfer is
  28. ;            a multiple of 16 in _rcvacsi(), use "andi".
  29. ; Feb-13-92    ml.    Modified setacnt() so that if transfer length in
  30. ;            bytes is greater than 512 but not a multiple of 512, 
  31. ;            add 1 to the count in order to get all the data.
  32. ;-
  33.  
  34.  
  35. .include    "defs.h"
  36. .include    "sysvar.h"
  37. .include    "mfp.h"
  38. .include    "acsi.h"
  39. .include    "68030.s"
  40.  
  41.  
  42. ;+
  43. ;  Tunable (delay) values for ACSI
  44. ;-
  45. ACLTMOUT    equ    600        ; long-timeout (3 S)
  46. ACSTMOUT    equ    20        ; short-timeout (100 mS)
  47. SLWACLTO    equ    5000        ; long-timeout (25 S) for slow ACSI
  48. SLWACSTO    equ    42        ; short-timeout (205 mS) for slow ACSI
  49.  
  50.  
  51. ;+
  52. ; Declarations
  53. ;-
  54. lastacstm:    dc.l    0        ; controller last accessed time
  55. control:    dc.b    0        ; flag for sending control byte
  56.         .globl    _slwacsi
  57. _slwacsi:    dc.b    0        ; assume not doing slow ACSI
  58. .even
  59.  
  60. .extern        _cmdblk
  61.  
  62.  
  63. ;+
  64. ; LONG _qdone() - Wait for command byte handshake
  65. ; LONG _fdone() - Wait for operation complete
  66. ; Passed:    nothing
  67. ;
  68. ; Returns:    EQ: no timeout
  69. ;        MI: timeout condition
  70. ;
  71. ; Uses:        D0
  72. ;
  73. ;-
  74.  
  75. .if    !DRIVER
  76. _slwfdone:                ; fdone for slow response
  77.     move.l    #SLWACLTO,d0
  78.     bra.s    qd0
  79. .endif
  80.  
  81. _fdone:    move.l    #ACLTMOUT,d0
  82.     bra.s    qd0
  83.  
  84. .if    !DRIVER
  85. _slwqdone:                ; qdone for slow response
  86.     moveq    #SLWACSTO,d0    
  87.     bra.s    qd0
  88. .endif
  89.  
  90. _qdone:    moveq    #ACSTMOUT,d0
  91.  
  92. qd0:    tst.b    _slwacsi        ; talking to slow ACSI device?
  93.     beq.s    qd1            ; if not, go wait for interrupt
  94.                     ; else
  95.     move.l    d0,-(sp)        ; save timeout value
  96.     moveq    #2,d0            ; busy-wait delay for slow ACSI
  97. sdelay:    add.l    _hz_200,d0        ; minimum 20 microsec.
  98.     cmp.l    _hz_200,d0
  99.     bge.s    sdelay
  100.     move.l    (sp)+,d0        ; restore timeout value
  101.  
  102. qd1:    add.l    _hz_200,d0
  103. qd2:    cmp.l    _hz_200,d0        ; timeout?
  104.     bcs.s    qdq            ; (i give up, return NE)
  105.     btst    #5,GPIP        ; interrupt?
  106.     bne.s    qd2            ; (not yet)
  107.  
  108.     moveq    #0,d0            ; return EQ (no timeout)
  109.     rts
  110.  
  111. qdq:    moveq    #-1,d0
  112.     rts
  113.  
  114.  
  115. ;+
  116. ; Wait for end of SASI command
  117. ;
  118. ; Passed:    d1 value to be written to wdl
  119. ;
  120. ; Returns:    EQ: success (error code in D0.W)
  121. ;        MI: timeout (-1 in D0.W)
  122. ;        NE: failure (SASI error code in D0.W)
  123. ;
  124. ; Uses:        d0
  125. ;
  126. ; Comments: (12/05/89)
  127. ;    The flushing of D cache is necessary per Jim Tittsler.  For
  128. ; detail, refer to mail sent by jwt on 12/04/89 about ACSI DMA.
  129. ;-
  130. .if    !DRIVER
  131.     .globl    _cachexst
  132. _cachexst:    dc.b    0
  133.  
  134. _slwendcmd:
  135.     bsr    _slwfdone        ; wait for operation complete
  136.     bra.s    end0
  137. .else
  138.     .extern    _cachexst
  139. .endif
  140.  
  141. _endcmd:
  142.     bsr    _fdone            ; wait for operation complete
  143. end0:    bmi.s    endce            ; (timed-out, so complain)
  144.  
  145. cmdcmp:    tst.b    _cachexst        ; '030 cache exists
  146.     beq.s    end1            ; if not, fine
  147.                     ; else, dump D cache
  148.     move.w    sr,-(sp)        ; go to IPL 7
  149.     ori.w    #$700,sr        ; no interrupts right now kudasai
  150.     movecacrd0            ; d0 = (cache control register)
  151.     ori.w    #$800,d0        ; dump the D cache
  152.     moved0cacr            ; update cache control register
  153.     move.w    (sp)+,sr        ; restore interrupt state
  154.  
  155. end1:    move.w    d1,WDL
  156.     move.w    WDC,d0            ; get the result
  157.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  158.                     ; do a ReadSense command to learn more
  159. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  160.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  161.     rts                
  162.  
  163.  
  164. ;+
  165. ;  Unlock DMA chip and return completion status;
  166. ;-
  167.     .globl    _hdone
  168. _hdone:    move.w    #$180,WDL    ; reset the chip for floppy
  169.     bsr    rstdelay
  170.     move.w    #$80,WDL    ; Landon's code seems to presume we put 
  171.                 ;  $80 there
  172.     clr    flock        ; NOW, signal that we are done
  173.     rts
  174.  
  175.  
  176. ;+
  177. ; delay()
  178. ;    5 - 10ms kludge delay for message byte sent back by controller.
  179. ;-
  180. _delay:    move.l    d0,-(sp)        ; preserve d0
  181.     move.l    lastacstm,d0        ; d0 = controller last accessed time
  182. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  183.     bcc.s    wait            ;    wait()
  184.     move.l    (sp)+,d0        ; restore d0
  185.     rts
  186.  
  187.  
  188. ;+
  189. ; smplacsi() - send a simple ACSI command (ie. no DMA involved)
  190. ;
  191. ;    d0.w = physical unit number
  192. ;    d1.l = transfer length (in bytes)
  193. ;    d2.w = command length (NCMD or LCMD)
  194. ;    a0.l = buffer address
  195. ;-
  196.     .globl    _smplacsi
  197. _smplacsi:
  198.     st    flock            ; lock FIFO
  199.     bsr    _delay            ; delay if necessary
  200.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  201.     andi.w    #7,d0            ; mask off the flags to get unit num
  202.     moveq    #0,d1            ; no DMA
  203.     bsr    sblkacsi        ; send command block
  204.     bra    _hdone            ; cleanup after IRQ
  205.  
  206.  
  207. ;+
  208. ; rcvacsi() - send a ACSI command which receives data back.
  209. ;
  210. ; Passed:
  211. ;    d0.w = physical unit number
  212. ;    d1.l = transfer length (in bytes)
  213. ;    d2.w = command length (NCMD or LCMD)
  214. ;    a0.l = buffer address
  215. ;
  216. ; Comments:
  217. ;    This routine assumes that if you are transferring more than 512
  218. ; bytes, the transfer length must be a multiple of 16 bytes.  It also 
  219. ; assumes the allocation length byte is always at byte 4 in the command
  220. ; block. (Therefore, it won't work with Receive Diagnostic ($1c) if data
  221. ; length is not a multiple of 16 bytes.  But Receive Diagnostic has never
  222. ; been used.)
  223. ;    The transfer length in register D1 MUST be greater than 0.
  224. ;-
  225.     .globl    _rcvacsi
  226. _rcvacsi:
  227.     st    flock            ; lock FIFO
  228.     move.w    d3,-(sp)        ; preserve d3
  229.     bsr    _delay            ; delay if necessary
  230.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  231.  
  232.     bsr    setadma            ; set DMA pointer
  233.     move.w    #$190,XWDL(a1)    ;WDL    ; toggle DMA chip for "receive"
  234.     bsr    rstdelay        ; delay
  235.     move.w    #$090,XWDL(a1)    ;WDL
  236.     bsr    rstdelay        ; delay
  237.  
  238. .if    RDWDL
  239.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  240. .endif    ;RDWDL
  241.  
  242.     bsr    setacnt            ; set DMA count
  243.  
  244.     andi.w    #7,d0            ; mask off the flags to get unit num
  245.                     ; find # times need to send it
  246.     cmpi.l    #512,d1            ; transferring < 512 bytes?
  247.     bcs.s    .0            ; if so, go find # times to send
  248.     moveq    #0,d1            ; else assume it's 16*n, send once
  249.     bra.s    .4
  250.  
  251. .0:    move.w    d1,d3            ; d3 = transfer length
  252.     cmpi.w    #16,d1            ; transferring < 16 bytes?
  253.     bcs.s    .1            ; if so, find # times to make 16 bytes
  254.  
  255.     andi.w    #$0f,d1            ; else, is it multiple of 16 bytes?
  256.     beq.s    .4            ; if so, just do once (d1.w = 0)
  257.     moveq    #1,d1            ; else, need to do twice
  258.     bra.s    .4
  259.  
  260. .1:    moveq    #16,d1            ; find # times to make 16 bytes
  261.     divu    d3,d1            ; d1.w = 16 / transfer length
  262.     subq.w    #1,d1            ; dbra likes one less
  263.  
  264. .2:    swap    d1            ; d1.w = remainder
  265.     tst.w    d1            ; any remainder?
  266.     bne.s    .3            ; if yes, go add one to the quotient
  267.     swap    d1            ; if no, # times to send = quotient
  268.     bra.s    .4
  269.  
  270. .3:    swap    d1            ; d1.w    = # times to send command
  271.     addq.w    #1,d1            ;    = quotient + 1
  272.  
  273. .4:    lea    _cmdblk,a0        ; a0 = address of command block
  274. .5:    movem.l    d0-d2/a0,-(sp)        ; save d0 through d2 and a0
  275.     moveq    #0,d1            ; direction of DMA is IN
  276.     bsr    _delay            ; delay if necessary
  277.     bsr    sblkacsi        ; send the command block
  278.     tst.w    d0            ; successful?
  279.     bne.s    .7            ; if not, quit
  280.     movem.l    (sp)+,d0-d2/a0        ; else restore d0 through d2 and a0
  281.     dbra    d1,.6            ; done yet?
  282.     moveq    #0,d0            ; command block sent successfully
  283.     bra.s    raend            ; phone home...
  284.  
  285. .6:    moveq    #-1,d0            ; unit number already in command block
  286.     move.b    d3,4(a0)        ; modify transfer length
  287.     bra.s    .5            ; send it enough times
  288.  
  289. .7:    adda    #16,sp            ; cleanup stack
  290. raend:    move.w    (sp)+,d3        ; restore d3
  291.     bra    _hdone            ; cleanup after IRQ
  292.  
  293.  
  294. ;+
  295. ; wrtacsi() - send an ACSI command which will write data to the target
  296. ;
  297. ; Passed:
  298. ;    d0.w = physical unit number
  299. ;    d1.l = transfer length (in bytes)
  300. ;    d2.w = command length (NCMD or LCMD)
  301. ;    a0.l = buffer address
  302. ;-
  303.     .globl    _wrtacsi
  304. _wrtacsi:
  305.     st    flock            ; lock FIFO
  306.     bsr    _delay
  307.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  308.  
  309.     bsr    setadma            ; set DMA pointer
  310.     move.w    #$90,XWDL(a1)    ;WDL    ; toggle DMA chip for "send"
  311.     bsr    rstdelay        ; delay 
  312.     move.w    #$190,XWDL(a1)    ;WDL
  313.     bsr    rstdelay        ; delay
  314.  
  315. .if    RDWDL
  316.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  317. .endif    ;RDWDL
  318.  
  319.     bsr    setacnt            ; set DMA count
  320.     
  321.     andi.w    #7,d0            ; mask off the flags to get unit num
  322.     move.l    #$0100,d1        ; d1 = direction of DMA is OUT
  323.     bsr    sblkacsi        ; send the command block
  324.  
  325. waend:    bra    _hdone            ; cleanup after IRQ
  326.  
  327.  
  328. ;+
  329. ; sblkacsi() - set DMA pointer and count and send command block
  330. ;
  331. ; Passed:
  332. ;    d0.w = physical unit number
  333. ;    d1.l = direction of DMA ($0000 for IN or $0100 for OUT)
  334. ;    d2.w = command length (NCMD or LCMD)
  335. ;    a1.l = pointer to DMA chip
  336. ;
  337. ; Returns:
  338. ;    d0.l =  0 if successful
  339. ;    d0.l = -1 if timeout
  340. ;
  341. ; Trashes:
  342. ;    d0, d1, d2, a2
  343. ;-
  344. sblkacsi:
  345.     move.b    #$88,d1            ; next byte is the opcode
  346.     move.w    d1,XWDL(a1)    ;WDL
  347.  
  348.     move.b    #$8a,d1            ; following bytes are operands
  349.     lea    _cmdblk,a2        ; a2 = address of command block
  350.  
  351.     tst.w    d0            ; is unit # already in command block
  352.     bmi.s    .0            ; if yes, just send command block
  353.                     ; else integrate unit # into cmd blk
  354.     lsl.b    #5,d0            ; shift unit number into place
  355.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  356.                     ; control byte is sent seperately
  357. .0:    subq.w    #2,d2            ; and dbra likes one less 
  358. .1:    swap    d1            ; d1.hw = operand
  359.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  360.     swap    d1            ;      is an operand
  361.     move.l    d1,(a1)        ;WDCWDL
  362.     bsr    _qdone
  363.     bmi.s    sbaend            ; if timeout, returns
  364.     dbra    d2,.1            ; else send rest of command block
  365.  
  366.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  367.     move.b    #0,d1            ; signal sending control byte
  368.     swap    d1            ; d1.hw = operand
  369.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  370.     swap    d1            ;      of command
  371.     move.l    d1,(a1)            ; send it
  372.  
  373.     move.b    #$8a,d1            ; d1 = wdl value
  374.     bsr    _endcmd            ; wait for command completion
  375. sbaend: rts                ; heading home
  376.  
  377.  
  378. ;+
  379. ; setadma() - set the ACSI DMA pointer
  380. ;
  381. ; Passed:
  382. ;    a0.l = buffer address
  383. ;-
  384.     .globl    setadma
  385. setadma:
  386.     move.l    a0,-(sp)        ; move it on stack
  387.     move.b    3(sp),DMALOW        ; set low-byte of address
  388.     move.b    2(sp),DMAMID        ; set mid-byte of address
  389.     move.b    1(sp),DMAHI        ; set high-byte of address
  390.     addq.l    #4,sp            ; clean up stack
  391.     rts
  392.  
  393.  
  394. ;+
  395. ; setacnt() - set the ACSI DMA counter
  396. ;
  397. ; Passed:
  398. ;    d1.l = transfer length (in bytes)
  399. ;    a1.l = pointer to DMA chip
  400. ;-
  401.     .globl    setacnt
  402. setacnt:
  403.     cmpi.l    #512,d1            ; transferring more than 512 bytes?
  404.     bhi.s    .0            ; if so, find transfer len in blocks
  405.     move.w    #1,(a1)        ;WDC    ; else set DMA count to 1 block
  406.     bra.s    sacend
  407. .0:    movem.l    d1-d2,-(sp)        ; save d1 and d2
  408.     move.l    d1,d2            ; d2 = transfer length (in bytes)
  409.     lsr.l    #8,d1            ; find transfer length (in blocks)
  410.     lsr.l    #1,d1            ; d1 >>= 9 = transfer len (in blocks)
  411.     andi.l    #$1ff,d2        ; multiples of 512?
  412.     beq.s    .1            ; if so, go set count
  413.     add.w    #1,d1            ; else increment count by one    
  414. .1:    move.w    d1,(a1)        ;WDC    ; set DMA count
  415.     movem.l    (sp)+,d1-d2        ; restore d1 and d2
  416. sacend:    rts
  417.  
  418.  
  419.  
  420. .if    !DRIVER                ; not to be included in driver
  421.  
  422. ;+
  423. ; fmtacsi() - format an ACSI unit
  424. ;
  425. ;    d0.w = physical unit number
  426. ;    d2.w = command length (NCMD or LCMD)
  427. ;-
  428.     .globl    _fmtacsi
  429.     .extern    _cmdblk
  430. _fmtacsi:
  431.     st    flock            ; lock FIFO
  432.     bsr    _delay            ; delay if necessary
  433.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  434.     andi.w    #7,d0            ; mask off the flags to get unit num
  435.     moveq    #0,d1            ; clear d1
  436.     move.b    #$88,d1            ; next byte is the opcode
  437.     move.w    d1,XWDL(a1)    ;WDL
  438.  
  439.     move.b    #$8a,d1            ; following bytes are operands
  440.     lea    _cmdblk,a2        ; a2 = address of command block
  441.                     ; integrate unit # into cmd blk
  442.     lsl.w    #5,d0            ; shift unit number into place
  443.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  444.                     ; control byte is sent seperately
  445.     subq.w    #2,d2            ; and dbra likes one less 
  446. .0:    swap    d1            ; d1.hw = operand
  447.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  448.     swap    d1            ;      is an operand
  449.     move.l    d1,(a1)        ;WDCWDL
  450.     bsr    _qdone
  451.     beq.s    .1            ; if successful, go on
  452.     rts                ; else it timed-out, returns
  453. .1:    dbra    d2,.0            ; send rest of command block
  454.  
  455.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  456.     move.b    #0,d1            ; signal sending control byte
  457.     swap    d1            ; d1.hw = operand
  458.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  459.     swap    d1            ;      of command
  460.     move.l    d1,(a1)            ; send it
  461.  
  462.     move.b    #$8a,d1            ; d1 = wdl value
  463. .2:    btst    #5,GPIP        ; wait forever for command completion
  464.     bne.s    .2
  465.     bsr    cmdcmp            ; command completed
  466.     bra    _hdone            ; cleanup after IRQ
  467.  
  468.  
  469. ;+
  470. ; stacsi() - start/stop an ACSI unit
  471. ;
  472. ;    d0.w = physical unit number
  473. ;    d2.w = command length (NCMD or LCMD)
  474. ;-
  475.     .globl    _stacsi
  476.     .extern    _cmdblk
  477. _stacsi:
  478.     st    flock            ; lock FIFO
  479.     bsr    _delay            ; delay if necessary
  480.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  481.     andi.w    #7,d0            ; mask off the flags to get unit num
  482.     moveq    #0,d1            ; clear d1
  483.     move.b    #$88,d1            ; next byte is the opcode
  484.     move.w    d1,XWDL(a1)    ;WDL
  485.  
  486.     move.b    #$8a,d1            ; following bytes are operands
  487.     lea    _cmdblk,a2        ; a2 = address of command block
  488.                     ; integrate unit # into cmd blk
  489.     lsl.w    #5,d0            ; shift unit number into place
  490.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  491.                     ; control byte is sent seperately
  492.     subq.w    #2,d2            ; and dbra likes one less 
  493. .0:    swap    d1            ; d1.hw = operand
  494.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  495.     swap    d1            ;      is an operand
  496.     move.l    d1,(a1)        ;WDCWDL
  497.     bsr    _slwqdone        ; needs a longer short timeout
  498.     beq.s    .1            ; if successful, go on
  499.     rts                ; else it timed-out, returns
  500. .1:    dbra    d2,.0            ; send rest of command block
  501.  
  502.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  503.     move.b    #0,d1            ; signal sending control byte
  504.     swap    d1            ; d1.hw = operand
  505.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  506.     swap    d1            ;      of command
  507.     move.l    d1,(a1)            ; send it
  508.  
  509.     move.b    #$8a,d1            ; d1 = wdl value
  510.     bsr    _slwendcmd        ; wait for command completion
  511.     bra    _hdone            ; cleanup after IRQ
  512.  
  513. .endif    ;!DRIVER
  514.  
  515.  
  516. ;+
  517. ; Rstdelay()
  518. ;    After talking to the DMA chip in a way that may reset it, 
  519. ; we need a 8 8Mhz clocks (ie. 1 microsec) delay, before we can
  520. ; talk to the chip again.
  521. ;-
  522.     .globl    rstdelay
  523. rstdelay:
  524.     tst.b    GPIP            ; delay for 1 microsec
  525.     tst.b    GPIP            ; this amounts to 16 16Mhz clocks
  526.     tst.b    GPIP
  527.     tst.b    GPIP
  528.     rts
  529.  
  530.